import problem as problem_core

class RoadNetState(problem_core.ProblemState):
    
    def __init__(self, junctionKey, targetKey, actionGenerator, map):
        self.map = map
        self.junctionKey = junctionKey
        self.targetKey = targetKey
        self.actionGenerator = actionGenerator

    def getSuccessors(self):
        '''
        Generates all the actions that can be performed from this state, and
        the States those actions will create.
        
        @return: A dictionary containing each action as a key, and its state.
        '''
        junction = self.map.GetJunction(self.junctionKey)
        res = dict()
        for link in junction.links:
            res[self.actionGenerator(self.junctionKey, link)] = RoadNetState(link.target, self.targetKey, self.actionGenerator, self.map)
        return res

    
    def isGoal(self):
        '''
        @return: Whether this Problem state is the searched goal or not.
        '''
        return self.junctionKey == self.targetKey
    
    def __cmp__(self, other):
        '''
        The comparison method must be implemented to ensure deterministic results.
        @return: Negative if self < other, zero if self == other and strictly 
        positive if self > other.
        '''
        if self.map.JunctionDistance(self.junctionKey, other.junctionKey) == 0:
            return 0
        else:
            return -1
    
    def __hash__(self):
        '''
        The hash method must be implemented for states to be inserted into sets 
        and dictionaries.
        @return: The hash value of the state.
        '''
        return hash((self.junctionKey, self.targetKey))
    
    def __str__(self):
        return 'State Junction: (' + self.junction.lat + ',' + self.junction.lon + ')'
    
    def __repr__(self):
        return self.__str__()

class ActionGenerator():
    def __init__(self, map, shw = 0, fw = 0, saw = 0):
        self.map = map
        self.shw = shw
        self.fw = fw
        self.saw = saw

    def ShortestCost(self, link):
        return link.distance/1000.0
    def FastestCost(self, link):
        return link.distance / (link.speed*1000.0)
    def SavingCost(self, link):
        return link.distance / (self.map.PetrolConsumption(link.speed)*1000.0)

    def WeightAction(self, src ,link):
        cost = self.shw * self.ShortestCost(link) + self.fw * self.FastestCost(link) + self.saw * self.SavingCost(link)
        return problem_core.ProblemAction(src,  link.target, cost )